#===============================================================================
# Copyright 2011 Jake Ross
# 
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# 
#   http://www.apache.org/licenses/LICENSE-2.0
# 
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#===============================================================================



#============= enthought library imports =======================

#============= standard library imports ========================
import math

#============= local library imports  ==========================
class AffineTransform:
    "Represents a 2D + 1 affine transformation"
    # use this for transforming points
    # A = [ a c e]
    #     [ b d f]
    #     [ 0 0 1]
    # self.A = [a b c d e f] = " [ A[0] A[1] A[2] A[3] A[4] A[5] ]"
    def __init__(self, init=None):
        if init:
            if len(init) == 6 :
                self.A = init
            if type(init) == type(self): # erpht!!! this seems so wrong
                self.A = init.A
        else:
            self.A = [1.0, 0, 0, 1.0, 0.0, 0.0] # set to identity

    def scale(self, sx, sy):
        self.A = [sx * self.A[0], sx * self.A[1], sy * self.A[2], sy * self.A[3], self.A[4], self.A[5] ]

    def rotate(self, theta):
        "counter clockwise rotation in standard SVG/libart coordinate system"
        # clockwise in postscript "y-upward" coordinate system
        # R = [ c  -s  0 ]
        #     [ s   c  0 ]
        #     [ 0   0  1 ]
        co = math.cos(math.radians(theta))
        si = math.sin(math.radians(theta))
        self.A = [self.A[0] * co + self.A[2] * si,
                  self.A[1] * co + self.A[3] * si,
                  - self.A[0] * si + self.A[2] * co,
                  - self.A[1] * si + self.A[3] * co,
                  self.A[4],
                  self.A[5] ]

    def translate(self, tx, ty):
        self.A = [ self.A[0], self.A[1], self.A[2], self.A[3],
                    self.A[0] * tx + self.A[2] * ty + self.A[4],
                    self.A[1] * tx + self.A[3] * ty + self.A[5] ]

    def rightMultiply(self, a, b, c, d, e, f):
        "multiply self.A by matrix M defined by coefficients a,b,c,d,e,f"
        # 

        #             [    m0*a+m2*b,    m0*c+m2*d, m0*e+m2*f+m4]
        #  ctm * M =  [    m1*a+m3*b,    m1*c+m3*d, m1*e+m3*f+m5]
        #             [            0,            0,            1]
        m = self.A
        self.A = [ m[0] * a + m[2] * b,
                   m[1] * a + m[3] * b,
                   m[0] * c + m[2] * d,
                   m[1] * c + m[3] * d,
                   m[0] * e + m[2] * f + m[4],
                   m[1] * e + m[3] * f + m[5] ]

    #########  functions that act on points ##########

    def transformPt(self, pt):
        #                   [
        #  pt = A * [x, y, 1]^T  =  [a*x + c*y+e, b*x+d*y+f, 1]^T
        #
        x, y = pt
        a, b, c, d, e, f = self.A
        return [ a * x + c * y + e, b * x + d * y + f]

    def scaleRotateVector(self, v):
        # scale a vector (translations are not done)
        x, y = v
        a, b, c, d, _e, _f = self.A
        return [a * x + c * y, b * x + d * y]


    def transformFlatList(self, seq):
        # transform a (flattened) sequence of points in form [x0,y0, x1,y1,..., x(N-1), y(N-1)]
        N = len(seq) # assert N even

        # would like to reshape the sequence, do w/ a loop for now
        res = []
        for ii in xrange(0, N, 2):
            pt = self.transformPt((seq[ii], seq[ii + 1]))
            res.extend(pt)

        return res

#============= views ===================================
#============= EOF ====================================
